#ifndef __M_FMT_H__
#define __M_FMT_H__


#include <string>
#include <assert.h>
#include <time.h>
#include <sstream>
#include "message.hpp"
#include "level.hpp"


/*
为什么FormatItem类和Formatter类的类成员没有LogMsg，而是在每个函数中传参LogMsg
因为类成员中有LogMsg，意味着创建一个类对象，这个对象只能为这一条LogMsg对应的日志信息服务
而在函数传参中传入LogMsg，创建一个类对象就可以为任意的LogMsg对应的日志信息服务
*/
namespace MyLog
{
    //抽象格式化子项基类
    class FormatItem
    {
    public:
        using ptr = std::shared_ptr<FormatItem>;
        virtual void format(std::ostream& out, LogMsg& msg) = 0;
    };

    //日志时间
    class DateFormatItem : public FormatItem
    {
    public:
        DateFormatItem(const std::string& dateFmt)
            :_dateFmt(dateFmt)
        {}

        // virtual void format(std::ostream& out, LogMsg& msg) override
        // {
        //     struct tm* tmp;
        //     tmp = localtime(&(msg._time));
        //     char buffer[32];
        //     if(strftime(buffer, sizeof(buffer), _dateFmt.c_str(), tmp) == 0)
        //         assert(false);
        //     out << buffer;
        // }
        virtual void format(std::ostream& out, LogMsg& msg) override
        {
            out << Time::FormatTime(msg._time, _dateFmt);
        }
        
    private:
        std::string _dateFmt;
    };

    //日志等级
    class LevelFormatItem : public FormatItem
    {
    public:
        virtual void format(std::ostream& out, LogMsg& msg) override
        {
            out << LogLevel::ToString(msg._level);
        }
    };

    //文件名
    class FileFormatItem : public FormatItem
    {
    public:
        virtual void format(std::ostream& out, LogMsg& msg) override
        {
            out << msg._fileName;
        }
    };

    //行号
    class LineFormatItem : public FormatItem
    {
    public:
        virtual void format(std::ostream& out, LogMsg& msg) override
        {
            out << std::to_string(msg._fileLine);
        }
    };

    //线程id
    class IdFormatItem : public FormatItem
    {
    public:
        virtual void format(std::ostream& out, LogMsg& msg) override
        {
            out << msg._tid;
        }
    };

    //日志器名称
    class LoggerFormatItem : public FormatItem
    {
    public:
        virtual void format(std::ostream& out, LogMsg& msg) override
        {
            out << msg._logger;
        }
    };

    //日志主体消息
    class PayloadFormatItem : public FormatItem
    {
    public:
        virtual void format(std::ostream& out, LogMsg& msg) override
        {
            out << msg._payload;
        }
    };

    //换行
    class NewlineFormatItem : public FormatItem
    {
    public:
        virtual void format(std::ostream& out, LogMsg& msg) override
        {
            out << "\n";
        }
    };

    //制表符
    class TabFormatItem : public FormatItem
    {
    public:
        virtual void format(std::ostream& out, LogMsg& msg) override
        {
            out << "\t";
        }
    };
    
    //其他字符
    class OtherFormatItem : public FormatItem
    {
    public:
        OtherFormatItem(const std::string& content)
            :_content(content)
        {}
        virtual void format(std::ostream& out, LogMsg& msg) override
        {
            out << _content;
        }
    private:
        std::string _content;
    };

   
    class Formatter
    {
        /*
            %D 日期
            %p 日志级别
            %f 文件名
            %l 行号
            %t 线程id
            %c 日志器名称
            %g 日志消息
            %n 换行
            %T 制表符
        */
    public:
        using ptr = std::shared_ptr<Formatter>;

        Formatter(const std::string& pattern = "[%D{%Y.%m.%d %H:%M:%S}][%t][%c][%f:%l][%p]<%g>%n")
            :_pattern(pattern)
        {}

        //对msg进行格式化
        void format(std::ostream& out, LogMsg& msg)
        {
            _items.clear();
            if(!parsePattern())
                return;
            // for(auto i : _items)
            // {
            //     i->format(out, msg);
            // }
            for(int i = 0; i < _items.size(); ++i)
            {
                assert(i < _items.size());
                _items[i]->format(out, msg);
            }
        }

        std::string format(LogMsg& msg)
        {
            //std::ostream是抽象类，不能实例化
            _items.clear();
            std::stringstream ss;
            format(ss, msg);
            return ss.str();
        }

        

        // TODO: 我怀疑是字符串解析效率有点低


        // 对格式化规则字符串进行解析
        bool parsePattern()
        {
            size_t size = _pattern.size();
            size_t index = 0;
            while(index < size)
            {
                // std::cout << index << std::endl;
                if(_pattern[index] == '%')
                {
                    //单独一个‘%’在最后
                    if(index + 1 >= size)
                    {
                        std::cout << "% 匹配失败" << std::endl;
                        return false;
                    }
                        
                    //如果是日期，要处理子串
                    if(_pattern[index + 1] == 'D')
                    {
                        //如果有指定日期格式
                        if(index + 2 < size && _pattern[index + 2] == '{')
                        {
                            index += 3;
                            size_t pos = index;
                            while(pos < size && _pattern[pos] != '}')
                                ++pos;

                            //无 '}'   
                            if(pos >= size)
                            {
                                std::cout << "子规则{}匹配失败" << std::endl;
                                return false;
                            }
                                
                            std::string dateFmt = _pattern.substr(index, pos - index);
                            _items.push_back(createItem('D', dateFmt));
                            index = pos + 1;
                        }
                        //如果没有，采用默认的
                        else
                        {
                            std::string dateFmt = "%Y.%m.%d %H:%M:%S";
                            _items.push_back(createItem(_pattern[index + 1], dateFmt));
                            index += 2;
                        }
                    }
                    //‘%’字面量
                    else if(_pattern[index + 1] == '%')
                    {
                        _items.push_back(createItem(' ', "%"));
                        index += 2;
                    }
                    //其他情况
                    else
                    {
                        FormatItem::ptr p = createItem(_pattern[++index], "");
                        if(p == nullptr)
                        {
                            std::cout << "未定义的格式化字符: " << _pattern[index] << std::endl;
                            assert(false);
                        }
                        _items.push_back(p);
                        ++index;
                    }
                }
                else
                    _items.push_back(createItem(' ', std::string(1, _pattern[index++])));

            }
            return true;
        }


    private:
        //根据不同的格式化字符串创建不同的格式化子项对象
        FormatItem::ptr createItem(char key, const std::string& content)
        {
            if(key == 'D')
                return std::make_shared<DateFormatItem>(content);
            else if(key == 'p')
                return std::make_shared<LevelFormatItem>();
            else if(key == 'f')
                return std::make_shared<FileFormatItem>();
            else if(key == 'l')
                return std::make_shared<LineFormatItem>();
            else if(key == 't')
                return std::make_shared<IdFormatItem>();
            else if(key == 'c')
                return std::make_shared<LoggerFormatItem>();
            else if(key == 'g')
                return std::make_shared<PayloadFormatItem>();
            else if(key == 'n')
                return std::make_shared<NewlineFormatItem>();
            else if(key == 'T')
                return std::make_shared<TabFormatItem>();
            else if(key == ' ')
                return std::make_shared<OtherFormatItem>(content);
            else
                return nullptr;
        }
    private:
        std::string _pattern; //格式化规则字符串
        std::vector<FormatItem::ptr> _items;
    };
}


#endif
